home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Disc to the Future 2
/
Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin
/
MAC
/
MPW_TOOL
/
TOOLS
/
TOOLS_WI
/
ICON_8
/
ICONX_FO
/
RMEMMGT.C
< prev
next >
Wrap
Text File
|
1990-03-11
|
46KB
|
1,598 lines
/*
* File: rmemmgt.c
* Contents: allocation routines, block description arrays, dump routines,
* garbage collection, sweep
*/
#include "::h:config.h"
#include "::h:rt.h"
#include "rproto.h"
#if MACINTOSH
#if MPW
#include <QuickDraw.h>
#include <ToolUtils.h>
#endif /* MPW */
#endif /* MACINTOSH */
#ifdef IconAlloc
/*
* If IconAlloc is defined the system allocation routines are not overloaded.
* The names are changed so that Icon's allocation routines are independently
* used. This works as long as no other system calls cause the break value
* to change.
*/
#define malloc mem_alloc
#define free mem_free
#define realloc mem_realloc
#define calloc mem_calloc
#endif /* IconAlloc */
/*
* Prototype.
*/
hidden union block *alcblk Params((uword nbytes,int tcode));
word coexp_ser = 1; /* serial numbers for co-expressions; &main is 1 */
word list_ser = 1; /* serial numbers for lists */
word set_ser = 1; /* serial numbers for sets */
word table_ser = 1; /* serial numbers for tables */
word coll_stat = 0; /* collections in static region */
word coll_str = 0; /* collections in string region */
word coll_blk = 0; /* collections in block region */
word coll_tot = 0; /* total collections */
#ifdef EvalTrace
extern FILE *trfile;
extern word colmno;
extern word lineno;
#endif /* EvalTrace */
#ifdef FixedRegions
word alcnum = 0; /* co-expressions allocated since g.c. */
#endif /* FixedRegions */
dptr *quallist; /* string qualifier list */
dptr *qualfree; /* qualifier list free pointer */
dptr *equallist; /* end of qualifier list */
int qualfail; /* flag: quailifier list overflow */
/*
* Note: function calls beginning with "MM" are just empty macros
* unless MemMon is defined.
*/
/*
* Allocated block size table (sizes given in bytes). A size of -1 is used
* for types that have no blocks; a size of 0 indicates that the
* second word of the block contains the size; a value greater than
* 0 is used for types with constant sized blocks.
*/
int bsizes[] = {
-1, /* T_Null (0), not block */
-1, /* T_Integer (1), not block */
#ifdef LargeInts
0, /* T_Bignum (2), bignum */
#else
-1, /* (2), not used */
#endif /* LargeInts */
sizeof(struct b_real), /* T_Real (3), real number */
sizeof(struct b_cset), /* T_Cset (4), cset */
sizeof(struct b_file), /* T_File (5), file block */
0, /* T_Proc (6), procedure block */
sizeof(struct b_list), /* T_List (7), list header block */
sizeof(struct b_table), /* T_Table (8), table header block */
0, /* T_Record (9), record block */
sizeof(struct b_telem), /* T_Telem (10), table element block */
0, /* T_Lelem (11), list element block */
sizeof(struct b_tvsubs), /* T_Tvsubs (12), substring trapped variable */
-1, /* T_Tvkywd (13), keyword trapped variable */
sizeof(struct b_tvtbl), /* T_Tvtbl (14), table element trapped variable */
sizeof(struct b_set), /* T_Set (15), set header block */
sizeof(struct b_selem), /* T_Selem (16), set element block */
0, /* T_Refresh (17), refresh block */
-1, /* T_Coexpr (18), co-expression block */
0, /* T_External (19), external block */
0, /* T_Slots (20), set/table hash block */
};
/*
* Table of offsets (in bytes) to first descriptor in blocks. -1 is for
* types not allocated, 0 for blocks with no descriptors.
*/
int firstd[] = {
-1, /* T_Null (0), not block */
-1, /* T_Integer (1), not block */
#ifdef LargeInts
0, /* T_Bignum (2), bignum */
#else
-1, /* (2), not used */
#endif /* LargeInts */
0, /* T_Real (3), real number */
0, /* T_Cset (4), cset */
3*WordSize, /* T_File (5), file block */
7*WordSize, /* T_Proc (6), procedure block */
0, /* T_List (7), list header block */
(4+HSegs)*WordSize, /* T_Table (8), table header block */
4*WordSize, /* T_Record (9), record block */
3*WordSize, /* T_Telem (10), table element block */
7*WordSize, /* T_Lelem (11), list element block */
3*WordSize, /* T_Tvsubs (12), substring trapped variable */
-1, /* T_Tvkywd (13), keyword trapped variable */
3*WordSize, /* T_Tvtbl (14), table element trapped variable */
0, /* T_Set (15), set header block */
3*WordSize, /* T_Selem (16), set element block */
(4+Wsizeof(struct pf_marker))*WordSize,
/* T_Refresh (17), refresh block */
-1, /* T_Coexpr (18), co-expression block */
0, /* T_External (19), external block */
0, /* T_Slots (20), set/table hash block */
};
/*
* Table of offsets (in bytes) to first pointer in blocks. -1 is for
* types not allocated, 0 for blocks with no pointers.
*/
int firstp[] = {
-1, /* T_Null (0), not block */
-1, /* T_Integer (1), not block */
#ifdef LargeInts
0, /* T_Bignum (2), bignum */
#else
-1, /* (2), not used */
#endif /* LargeInts */
0, /* T_Real (3), real number */
0, /* T_Cset (4), cset */
0, /* T_File (5), file block */
0, /* T_Proc (6), procedure block */
3*WordSize, /* T_List (7), list header block */
4*WordSize, /* T_Table (8), table header block */
3*WordSize, /* T_Record (9), record block */
1*WordSize, /* T_Telem (10), table element block */
2*WordSize, /* T_Lelem (11), list element block */
0, /* T_Tvsubs (12), substring trapped variable */
-1, /* T_Tvkywd (13), keyword trapped variable */
1*WordSize, /* T_Tvtbl (14), table element trapped variable */
4*WordSize, /* T_Set (15), set header block */
1*WordSize, /* T_Selem (16), set element block */
0, /* T_Refresh (17), refresh block */
-1, /* T_Coexpr (18), co-expression block */
0, /* T_External (19), external block */
2*WordSize, /* T_Slots (20), set/table hash block */
};
/*
* Table of number of pointers in blocks. -1 is for types not allocated and
* types without pointers, 0 for pointers through the end of the block.
*/
int ptrno[] = {
-1, /* T_Null (0), not block */
-1, /* T_Integer (1), not block */
-1, /* T_Bignum (2), large integer, or not used */
-1, /* T_Real (3), real number */
-1, /* T_Cset (4), cset */
-1, /* T_File (5), file block */
-1, /* T_Proc (6), procedure block */
2, /* T_List (7), list header block */
HSegs, /* T_Table (8), table header block */
1, /* T_Record (9), record block */
1, /* T_Telem (10), table element block */
2, /* T_Lelem (11), list element block */
-1, /* T_Tvsubs (12), substring trapped variable */
-1, /* T_Tvkywd (13), keyword trapped variable */
1, /* T_Tvtbl (14), table element trapped variable */
HSegs, /* T_Set (15), set header block */
1, /* T_Selem (16), set element block */
-1, /* T_Refresh (17), refresh block */
-1, /* T_Coexpr (18), co-expression block */
-1, /* T_External (19), external block */
0, /* T_Slots (20), set/table hash block */
};
/*
* Table of block names used by debugging functions.
*/
char *blkname[] = {
"illegal object", /* T_Null (0), not block */
"illegal object", /* T_Integer (1), not block */
#ifdef LargeInts
"large integer", /* T_Bignum (2), bignum */
#else
"illegal object", /* not used */
#endif /* LargeInts */
"real number", /* T_Real (3) */
"cset", /* T_Cset (4) */
"file", /* T_File (5) */
"procedure", /* T_Proc (6) */
"list", /* T_List (7) */
"table", /* T_Table (8) */
"record", /* T_Record (9) */
"table element", /* T_Telem (10) */
"list element", /* T_Lelem (11) */
"substring trapped variable", /* T_Tvsubs (12) */
"keyword trapped variable", /* T_Tvkywd (13) */
"table element trapped variable", /* T_Tvtbl (14) */
"set", /* T_Set (15) */
"set elememt", /* T_Selem (16) */
"refresh block", /* T_Refresh (17) */
"co-expression", /* T_Coexpr (18) */
"external block", /* T_External (19) */
"hash block", /* T_Slots (20) */
};
/*
* Sizes of hash chain segments.
* Table size must equal or exceed HSegs.
*/
uword segsize[] = {
((uword)HSlots), /* segment 0 */
((uword)HSlots), /* segment 1 */
((uword)HSlots) << 1, /* segment 2 */
((uword)HSlots) << 2, /* segment 3 */
((uword)HSlots) << 3, /* segment 4 */
((uword)HSlots) << 4, /* segment 5 */
((uword)HSlots) << 5, /* segment 6 */
((uword)HSlots) << 6, /* segment 7 */
((uword)HSlots) << 7, /* segment 8 */
((uword)HSlots) << 8, /* segment 9 */
((uword)HSlots) << 9, /* segment 10 */
((uword)HSlots) << 10, /* segment 11 */
};
#ifdef FixedRegions
#include "rmemfix.c"
#else /* FixedRegions */
#include "rmemexp.c"
#endif /* FixedRegions */
/*
* alcblk - returns pointer to nbytes of free storage in block region.
*/
static union block *alcblk(nbytes,tcode)
uword nbytes;
int tcode;
{
register uword fspace, *sloc;
/*
* See if there is enough room in the block region.
*/
fspace = DiffPtrs(blkend,blkfree);
if (fspace < nbytes)
syserr("block allocation botch");
/*
* If monitoring, show the allocation.
*/
MMAlc((word)nbytes,tcode);
#ifdef EvalTrace
if (trfile) {
fprintf(trfile,"a\t%ld\t%ld\t%d\t%ld\n",colmno,lineno,tcode,nbytes);
}
#endif /* EvalTrace */
/*
* Decrement the free space in the block region by the number of bytes
* allocated and return the address of the first byte of the allocated
* block.
*/
sloc = (uword *)blkfree;
blkneed -= nbytes;
blkfree += nbytes;
BlkType(sloc) = tcode;
return (union block *)(sloc);
}
/*
* alcreal - allocate a real value in the block region.
*/
struct b_real *alcreal(val)
double val;
{
register struct b_real *blk;
blk = (struct b_real *)alcblk((uword)sizeof(struct b_real), T_Real);
#ifdef Double
/* access real values one word at a time */
{ int *rp, *rq;
rp = (word *) &(blk->realval);
rq = (word *) &val;
*rp++ = *rq++;
*rp = *rq;
}
#else /* Double */
blk->realval = val;
#endif /* Double */
return blk;
}
#ifdef LargeInts
/*
* alcbignum - allocate an n-digit bignum in the block region
*/
struct b_bignum *alcbignum(n)
word n;
{
register struct b_bignum *blk;
register uword size;
size = sizeof(struct b_bignum) + ((n - 1) * sizeof(DIGIT));
/* ensure whole number of words allocated */
size = (size + WordSize - 1) & -WordSize;
blk = (struct b_bignum *)alcblk(size, T_Bignum);
blk->blksize = size;
blk->msd = blk->sign = 0;
blk->lsd = n - 1;
return blk;
}
#endif /* LargeInts */
/*
* alccset - allocate a cset in the block region.
*/
struct b_cset *alccset()
{
register struct b_cset *blk;
register int i;
blk = (struct b_cset *)alcblk((uword)sizeof(struct b_cset), T_Cset);
blk->size = -1; /* flag size as not yet computed */
/*
* Zero the bit array.
*/
for (i = 0; i < CsetSize; i++)
blk->bits[i] = 0;
return blk;
}
/*
* alcfile - allocate a file block in the block region.
*/
struct b_file *alcfile(fd, status, name)
FILE *fd;
int status;
dptr name;
{
register struct b_file *blk;
blk = (struct b_file *)alcblk((uword)sizeof(struct b_file), T_File);
blk->fd = fd;
blk->status = status;
blk->fname = *name;
return blk;
}
/*
* alcrecd - allocate record with nflds fields in the block region.
*/
struct b_record *alcrecd(nflds, recptr)
int nflds;
union block **recptr;
{
register struct b_record *blk;
register int size;
size = Vsizeof(struct b_record) + nflds*sizeof(struct descrip);
blk = (struct b_record *)alcblk((uword)size, T_Record);
blk->blksize = size;
blk->recdesc = (union block *)recptr;
return blk;
}
/*
* alcextrnl - allocate an external block.
*/
struct b_external *alcextrnl(n)
int n;
{
register struct b_external *blk;
blk = (struct b_external *)alcblk((uword)(n * sizeof(word)), T_External);
blk->blksize = (n + 3) * sizeof(word);
blk->descoff = 0;
/* probably ought to clear the rest of the block */
return blk;
}
/*
* alclist - allocate a list header block in the block region.
*/
struct b_list *alclist(size)
uword size;
{
static word list_ser = 1;
register struct b_list *blk;
blk = (struct b_list *)alcblk((uword)sizeof(struct b_list), T_List);
blk->size = size;
blk->listhead = NULL;
blk->listtail = NULL;
blk->id = list_ser++;
return blk;
}
/*
* alclstb - allocate a list element block in the block region.
*/
struct b_lelem *alclstb(nslots, first, nused)
uword nslots, first, nused;
{
register struct b_lelem *blk;
register word i, size;
size = Vsizeof(struct b_lelem) + nslots * sizeof(struct descrip);
blk = (struct b_lelem *)alcblk((uword)size, T_Lelem);
blk->blksize = size;
blk->nslots = nslots;
blk->first = first;
blk->nused = nused;
blk->listprev = NULL;
blk->listnext = NULL;
/*
* Set all elements to &null.
*/
for (i = 0; i < nslots; i++)
blk->lslots[i] = nulldesc;
return blk;
}
/*
* alchash - allocate a hashed structure (set or table header) in the block
* region.
*/
union block *alchash(tcode)
int tcode;
{
static word table_ser = 1;
static word set_ser = 1;
register int i;
register union block *blk;
word serial;
uword blksize;
if (tcode == T_Table) {
serial = table_ser++;
blksize = sizeof(struct b_table);
}
else { /* tcode == T_Set */
serial = set_ser++;
blksize = sizeof(struct b_set);
}
blk = alcblk(blksize, tcode);
blk->set.size = 0;
blk->set.id = serial;
blk->set.mask = 0;
for (i = 0; i < HSegs; i++)
blk->set.hdir[i] = NULL;
return blk;
}
/*
* alcsegment - allocate a slot block in the block region.
*/
struct b_slots *alcsegment(nslots)
word nslots;
{
uword size;
register struct b_slots *blk;
size = sizeof(struct b_slots) + WordSize * (nslots - HSlots);
blk = (struct b_slots *)alcblk(size, T_Slots);
blk->blksize = size;
while (--nslots >= 0)
blk->hslots[nslots] = NULL;
return blk;
}
/*
* alctelem - allocate a table element block in the block region.
*/
struct b_telem *alctelem()
{
register struct b_telem *blk;
blk = (struct b_telem *)alcblk((uword)sizeof(struct b_telem), T_Telem);
blk->hashnum = 0;
blk->clink = NULL;
blk->tref = nulldesc;
blk->tval = nulldesc;
return blk;
}
/*
* alcselem - allocate a set element block.
*/
struct b_selem *alcselem(mbr,hn)
dptr mbr;
uword hn;
{
register struct b_selem *blk;
blk = (struct b_selem *)alcblk((uword)sizeof(struct b_selem), T_Selem);
blk->clink = NULL;
blk->setmem = *mbr;
blk->hashnum = hn;
return blk;
}
/*
* alcsubs - allocate a substring trapped variable in the block region.
*/
struct b_tvsubs *alcsubs(len, pos, var)
word len, pos;
dptr var;
{
register struct b_tvsubs *blk;
blk = (struct b_tvsubs *)alcblk((uword)sizeof(struct b_tvsubs), T_Tvsubs);
blk->sslen = len;
blk->sspos = pos;
blk->ssvar = *var;
return blk;
}
/*
* alctvtbl - allocate a table element trapped variable block in the block
* region.
*/
struct b_tvtbl *alctvtbl(tbl, ref, hashnum)
register dptr tbl, ref;
uword hashnum;
{
register struct b_tvtbl *blk;
blk = (struct b_tvtbl *)alcblk((uword)sizeof(struct b_tvtbl), T_Tvtbl);
blk->hashnum = hashnum;
blk->clink = BlkLoc(*tbl);
blk->tref = *ref;
blk->tval = nulldesc;
return blk;
}
/*
* alcstr - allocate a string in the string space.
*/
char *alcstr(s, slen)
register char *s;
register word slen;
{
register char *d;
register uword fspace;
char *ofree;
MMStr(slen);
#ifdef EvalTrace
if (trfile) {
fprintf(trfile,"a\t%ld\t%ld\t%ld\n",colmno,lineno,slen);
}
#endif /* EvalTrace */
/*
* See if there is enough room in the string space.
*/
fspace = DiffPtrs(strend,strfree);
if (fspace < slen)
syserr("string allocation botch");
strneed -= slen;
/*
* Copy the string into the string space, saving a pointer to its
* beginning. Note that s may be null, in which case the space
* is still to be allocated but nothing is to be copied into it.
*/
ofree = d = strfree;
if (s) {
while (slen-- > 0)
*d++ = *s++;
}
else
d += slen;
strfree = d;
return ofree;
}
/*
* alccoexp - allocate a co-expression stack block.
*/
struct b_coexpr *alccoexp()
{
struct b_coexpr *ep;
static word coexp_ser = 2; /* &main is 1 */
#ifdef ATTM32
ep = (struct b_coexpr *)coexp_salloc(); /* 3B2/15/4000 stack */
#else /* ATTM32 */
ep = (struct b_coexpr *)malloc((msize)stksize);
#endif /* ATTM32 */
/*
* If malloc failed or if there have been too many co-expression allocations
* since a collection, attempt to free some co-expression blocks and retry.
*/
#ifdef FixedRegions
if (ep == NULL || alcnum > AlcMax) {
#else /* FixedRegions */
if (ep == NULL) {
#endif /* Fixed Regions */
collect(Static);
#ifdef ATTM32 /* not needed, but here to play it safe */
ep = (struct b_coexpr *)coexp_salloc(); /* 3B2/15/4000 stack */
#else /* ATTM32 */
ep = (struct b_coexpr *)malloc((msize)stksize);
#endif /* ATTM32 */
}
if (ep == NULL) {
k_errornumber = -305;
k_errortext = "";
k_errorvalue = nulldesc;
return NULL;
}
#ifdef FixedRegions
alcnum++; /* increment allocation count since last g.c. */
#endif /* FixedRegions */
ep->title = T_Coexpr;
ep->es_actstk = NULL;
ep->size = 0;
ep->id = coexp_ser++;
ep->nextstk = stklist;
stklist = ep;
MMStat((char *)ep, stksize, 'X');
return ep;
}
/*
* alcactiv - allocate a co-expression activation block.
*/
struct astkblk *alcactiv()
{
struct astkblk *abp;
abp = (struct astkblk *)malloc((msize)sizeof(struct astkblk));
#ifdef FixedRegions
/*
* If malloc failed, attempt to free some co-expression blocks and retry.
*/
if (abp == NULL) {
collect(Static);
abp = (struct astkblk *)malloc((msize)sizeof(struct astkblk));
}
#endif /* FixedRegions */
if (abp == NULL) {
k_errornumber = -305;
k_errortext = "";
k_errorvalue = nulldesc;
return NULL;
}
abp->nactivators = 0;
abp->astk_nxt = NULL;
return abp;
}
/*
* alcrefresh - allocate a co-expression refresh block.
*/
struct b_refresh *alcrefresh(entryx, na, nl)
word *entryx;
int na, nl;
{
int size;
struct b_refresh *blk;
size = Vsizeof(struct b_refresh) + (na + nl) * sizeof(struct descrip);
blk = (struct b_refresh *)alcblk((uword)size, T_Refresh);
blk->blksize = size;
blk->ep = entryx;
blk->numlocals = nl;
return blk;
}
/*
* blkreq - insure that at least bytes of space are left in the block region.
* The amount of space needed is transmitted to the collector via
* the global variable blkneed.
*/
int blkreq(bytes)
uword bytes;
{
blkneed = bytes;
if (bytes > (uword)DiffPtrs(blkend,blkfree)) {
coll_blk++;
collect(Blocks);
if (bytes > (uword)DiffPtrs(blkend,blkfree))
RetError(-307, nulldesc);
}
return Success;
}
/*
* strreq - insure that at least n of space are left in the string
* space. The amount of space needed is transmitted to the collector
* via the global variable strneed.
*/
int strreq(n)
uword n;
{
strneed = n; /* save in case of collection */
if (n > (uword)DiffPtrs(strend,strfree)) {
coll_str++;
collect(Strings);
if (n > (uword)DiffPtrs(strend,strfree)) {
#ifdef FixedRegions
if (qualfail)
RetError(-304, nulldesc);
#endif /* FixedRegions */
RetError(-306, nulldesc);
}
}
return Success;
}
/*
* cofree - collect co-expression blocks. This is done after
* the marking phase of garbage collection and the stacks that are
* reachable have pointers to data blocks, rather than T_Coexpr,
* in their type field.
*/
novalue cofree()
{
register struct b_coexpr **ep, *xep;
extern word mstksize; /* main stack size */
register struct astkblk *abp, *xabp;
/*
* Reset the type for &main.
*/
BlkLoc(k_main)->coexpr.title = T_Coexpr;
/*
* The co-expression blocks are linked together through their
* nextstk fields, with stklist pointing to the head of the list.
* The list is traversed and each stack that was not marked
* is freed.
*/
ep = &stklist;
while (*ep != NULL) {
if (BlkType(*ep) == T_Coexpr) {
xep = *ep;
*ep = (*ep)->nextstk;
/*
* Free the astkblks. There should always be one and it seems that
* it's not possible to have more than one, but nonetheless, the
* code provides for more than one.
*/
for (abp = xep->es_actstk; abp; ) {
xabp = abp;
abp = abp->astk_nxt;
free((pointer)xabp);
}
free((pointer)xep);
}
else {
BlkType(*ep) = T_Coexpr;
MMStat((char *)(*ep), stksize, 'X');
ep = &(*ep)->nextstk;
}
}
MMStat((char *)stack, mstksize, 'X'); /* Also record main stack */
}
/*
* collect - do a garbage collection.
*/
novalue collect(region)
int region;
{
register dptr dp;
struct b_coexpr *cp;
MMBGC(region);
#ifdef EvalTrace
if (trfile) {
fprintf(trfile,"c\t%ld\t%ld\t%d\n",colmno,lineno,region);
}
#endif /* EvalTrace */
coll_tot++;
#ifdef FixedRegions
alcnum = 0;
#endif /* FixedRegions */
/*
* Garbage collection cannot be done until initialization is complete.
*/
if (sp == NULL)
return;
#if MACINTOSH
#if MPW
SetCursor(*GetCursor(watchCursor)); /* Set watch cursor */
#endif /* MPW */
#endif /* MACINTOSH */
/*
* Sync the values (used by sweep) in the coexpr block for ¤t
* with the current values.
*/
cp = (struct b_coexpr *)BlkLoc(k_current);
cp->es_pfp = pfp;
cp->es_gfp = gfp;
cp->es_efp = efp;
cp->es_sp = sp;
/*
* Reset qualifier list.
*/
#ifndef FixedRegions
quallist = (dptr *)blkfree;
#endif /* FixedRegions */
qualfree = quallist;
qualfail = 0;
/*
* Mark the stacks for &main and the current co-expression.
*/
markblock(&k_main);
markblock(&k_current);
/*
* Mark &subject and the cached s2 and s3 strings for map.
*/
postqual(&k_subject);
if (Qual(maps2)) /* caution: the cached arguments of */
postqual(&maps2); /* map may not be strings. */
else if (Pointer(maps2))
markblock(&maps2);
if (Qual(maps3))
postqual(&maps3);
else if (Pointer(maps3))
markblock(&maps3);
/*
* Mark the tended descriptors and the global and static variables.
*/
for (dp = &tended[1]; dp <= &tended[ntended]; dp++)
if (Qual(*dp))
postqual(dp);
else if (Pointer(*dp))
markblock(dp);
for (dp = globals; dp < eglobals; dp++)
if (Qual(*dp))
postqual(dp);
else if (Pointer(*dp))
markblock(dp);
for (dp = statics; dp < estatics; dp++)
if (Qual(*dp))
postqual(dp);
else if (Pointer(*dp))
markblock(dp);
reclaim(region);
MMEGC();
#ifndef FixedRegions
if (qualfail && (region == Strings || statneed) &&
DiffPtrs((char *)quallist,blkfree) > Sqlinc)
/*
* The string region could not be collected, but it looks like it
* needs to be. Collecting the block region gave more room for
* the qualifier list, so try again.
*/
collect(region);
#endif /* FixedRegions */
}
/*
* markblock - mark each accessible block in the block region and build
* back-list of descriptors pointing to that block. (Phase I of garbage
* collection.)
*/
novalue markblock(dp)
dptr dp;
{
register dptr dp1;
register char *block, *endblock;
word type, fdesc;
int numptr;
register union block **ptr, **lastptr;
/*
* Get the block to which dp points.
*/
block = (char *)BlkLoc(*dp);
if (InRange(blkbase,block,blkfree)) {
if (Var(*dp) && !Tvar(*dp)) {
/*
* The descriptor is a variable; block now points to the head of the
* block containing the descriptor.
*/
if (Offset(*dp) == 0)
return;
}
type = BlkType(block);
if ((uword)type <= MaxType) {
/*
* The type is valid, which indicates that this block has not
* been marked. Point endblock to the byte past the end
* of the block.
*/
endblock = block + BlkSize(block);
MMMark(block,(int)type);
}
/*
* Add dp to the back chain for the block and point the
* block (via the type field) to dp.vword.
*/
BlkLoc(*dp) = (union block *)type;
BlkType(block) = (uword)&BlkLoc(*dp);
if ((unsigned int)type <= MaxType) {
/*
* The block was not marked; process pointers and descriptors
* within the block.
*/
if ((fdesc = firstp[type]) > 0) {
/*
* The block contains pointers; mark each pointer.
*/
ptr = (union block **)(block + fdesc);
numptr = ptrno[type];
if (numptr > 0)
lastptr = ptr + numptr;
else
lastptr = (union block **)endblock;
for (; ptr < lastptr; ptr++)
if (*ptr != NULL)
markptr(ptr);
}
if ((fdesc = firstd[type]) > 0)
/*
* The block contains descriptors; mark each descriptor.
*/
for (dp1 = (dptr)(block + fdesc);
(char *)dp1 < endblock; dp1++) {
if (Qual(*dp1))
postqual(dp1);
else if (Pointer(*dp1))
markblock(dp1);
}
}
}
else if (dp->dword == D_Coexpr && (unsigned int)BlkType(block) <= MaxType) {
struct b_coexpr *cp;
struct astkblk *abp;
int i;
struct descrip adesc;
/*
* dp points to a co-expression block that has not been
* marked. Point the block to dp. Sweep the interpreter
* stack in the block. Then mark the block for the
* activating co-expression and the refresh block.
*/
BlkType(block) = (uword)dp;
sweep((struct b_coexpr *)block);
#ifdef Coexpr
/*
* Mark the activators of this co-expression. The activators are
* stored as a list of addresses, but markblock requires the address
* of a descriptor. To accommodate markblock, the dummy descriptor
* adesc is filled in with each activator address in turn and then
* marked. Since co-expressions and the descriptors that reference
* them don't participate in the back-chaining scheme, it's ok to
* reuse the descriptor in this manner.
*/
cp = (struct b_coexpr *)block;
adesc.dword = D_Coexpr;
for (abp = cp->es_actstk; abp != NULL; abp = abp->astk_nxt) {
for (i = 1; i <= abp->nactivators; i++) {
BlkLoc(adesc) = (union block *)abp->arec[i-1].activator;
markblock(&adesc);
}
}
markblock(&((struct b_coexpr *)block)->freshblk);
#endif /* Coexpr */
}
}
/*
* markptr - just like mark block except the object pointing at the block
* is just a block pointer, not a descriptor.
*/
novalue markptr(ptr)
union block **ptr;
{
register dptr dp;
register char *block, *endblock;
word type, fdesc;
int numptr;
register union block **ptr1, **lastptr;
/*
* Get the block to which ptr points.
*/
block = (char *)*ptr;
if (InRange(blkbase,block,blkfree)) {
type = BlkType(block);
if ((uword)type <= MaxType) {
/*
* The type is valid, which indicates that this block has not
* been marked. Point endblock to the byte past the end
* of the block.
*/
endblock = block + BlkSize(block);
MMMark(block,(int)type);
}
/*
* Add ptr to the back chain for the block and point the
* block (via the type field) to ptr.
*/
*ptr = (union block *)type;
BlkType(block) = (uword)ptr;
if ((unsigned int)type <= MaxType) {
/*
* The block was not marked; process pointers and descriptors
* within the block.
*/
if ((fdesc = firstp[type]) > 0) {
/*
* The block contains pointers; mark each pointer.
*/
ptr1 = (union block **)(block + fdesc);
numptr = ptrno[type];
if (numptr > 0)
lastptr = ptr1 + numptr;
else
lastptr = (union block **)endblock;
for (; ptr1 < lastptr; ptr1++)
if (*ptr1 != NULL)
markptr(ptr1);
}
if ((fdesc = firstd[type]) > 0)
/*
* The block contains descriptors; mark each descriptor.
*/
for (dp = (dptr)(block + fdesc);
(char *)dp < endblock; dp++) {
if (Qual(*dp))
postqual(dp);
else if (Pointer(*dp))
markblock(dp);
}
}
}
}
/*
* adjust - adjust pointers into the block region, beginning with block oblk
* and basing the "new" block region at nblk. (Phase II of garbage
* collection.)
*/
novalue adjust(source,dest)
char *source, *dest;
{
register union block **nxtptr, **tptr;
/*
* Loop through to the end of allocated block region, moving source
* to each block in turn and using the size of a block to find the
* next block.
*/
while (source < blkfree) {
if ((uword)(nxtptr = (union block **)BlkType(source)) > MaxType) {
/*
* The type field of source is a back pointer. Traverse the
* chain of back pointers, changing each block location from
* source to dest.
*/
while ((uword)nxtptr > MaxType) {
tptr = nxtptr;
nxtptr = (union block **) *nxtptr;
*tptr = (union block *)dest;
}
BlkType(source) = (uword)nxtptr | F_Mark;
dest += BlkSize(source);
}
source += BlkSize(source);
}
}
/*
* compact - compact good blocks in the block region. (Phase III of garbage
* collection.)
*/
novalue compact(source)
char *source;
{
register char *dest;
register word size;
/*
* Start dest at source.
*/
dest = source;
/*
* Loop through to end of allocated block space, moving source
* to each block in turn, using the size of a block to find the next
* block. If a block has been marked, it is copied to the
* location pointed to by dest and dest is pointed past the end
* of the block, which is the location to place the next saved
* block. Marks are removed from the saved blocks.
*/
while (source < blkfree) {
size = BlkSize(source);
if (BlkType(source) & F_Mark) {
BlkType(source) &= ~F_Mark;
if (source != dest)
mvc((uword)size,source,dest);
dest += size;
}
source += size;
}
/*
* dest is the location of the next free block. Now that compaction
* is complete, point blkfree to that location.
*/
blkfree = dest;
}
/*
* postqual - mark a string qualifier. Strings outside the string space
* are ignored.
*/
novalue postqual(dp)
dptr dp;
{
char *newend;
if (InRange(strbase,StrLoc(*dp),strend)) {
/*
* The string is in the string space. Add it to the string qualifier
* list, but before adding it, expand the string qualifier list if
* necessary.
*/
if (qualfree >= equallist) {
#ifdef FixedRegions
qualfail = 1;
return;
#else /* FixedRegions */
newend = (char *)equallist + Sqlinc;
/*
* Make sure region has not changed and that it can be expanded.
*/
if (currend != sbrk((word)0) || (int)brk((char *)newend) == -1) {
qualfail = 1;
return;
}
equallist = (dptr *)newend;
currend = sbrk((word)0);
#ifdef QuallistExp
fprintf(stderr,"size of quallist = %ld\n",
(long)DiffPtrs((char *)equallist,(char *)quallist));
fflush(stderr);
#endif /* QuallistExp */
#endif /* FixedRegions */
}
*qualfree++ = dp;
}
}
/*
* scollect - collect the string space. quallist is a list of pointers to
* descriptors for all the reachable strings in the string space. For
* ease of description, it is referred to as if it were composed of
* descriptors rather than pointers to them.
*/
novalue scollect(extra)
word extra;
{
register char *source, *dest;
register dptr *qptr;
char *cend;
if (qualfree <= quallist) {
/*
* There are no accessible strings. Thus, there are none to
* collect and the whole string space is free.
*/
strfree = strbase;
return;
}
/*
* Sort the pointers on quallist in ascending order of string
* locations.
*/
qsort((char *)quallist, (int)(DiffPtrs((char *)qualfree,(char *)quallist)) /
sizeof(dptr *), sizeof(dptr), qlcmp);
/*
* The string qualifiers are now ordered by starting location.
*/
dest = strbase;
source = cend = StrLoc(**quallist);
/*
* Loop through qualifiers for accessible strings.
*/
for (qptr = quallist; qptr < qualfree; qptr++) {
if (StrLoc(**qptr) > cend) {
/*
* qptr points to a qualifier for a string in the next clump.
* The last clump is moved, and source and cend are set for
* the next clump.
*/
MMSMark(source,DiffPtrs(cend,source));
while (source < cend)
*dest++ = *source++;
source = cend = StrLoc(**qptr);
}
if ((StrLoc(**qptr) + StrLen(**qptr)) > cend)
/*
* qptr is a qualifier for a string in this clump; extend
* the clump.
*/
cend = StrLoc(**qptr) + StrLen(**qptr);
/*
* Relocate the string qualifier.
*/
StrLoc(**qptr) = StrLoc(**qptr) + DiffPtrs(dest,source) + (uword)extra;
}
/*
* Move the last clump.
*/
MMSMark(source,DiffPtrs(cend,source));
while (source < cend)
*dest++ = *source++;
strfree = dest;
}
/*
* qlcmp - compare the location fields of two string qualifiers for qsort.
*/
int qlcmp(q1,q2)
dptr *q1, *q2;
{
#if IntBits == 16
long l;
l = (long)(DiffPtrs(StrLoc(**q1),StrLoc(**q2)));
if (l < 0)
return -1;
else if (l > 0)
return 1;
else
return 0;
#else /* IntBits = 16 */
return (int)(DiffPtrs(StrLoc(**q1),StrLoc(**q2)));
#endif /* IntBits == 16 */
}
/*
* mvc - move n bytes from src to dest
*
* The algorithm is to copy the data (using memcopy) in the largest
* chunks possible, which is the size of area of the source data not in
* the destination area (ie non-overlapped area). (Chunks are expected to
* be fairly large.)
*/
novalue mvc(n, src, dest)
uword n;
register char *src, *dest;
{
register char *srcend, *destend; /* end of data areas */
word copy_size; /* of size copy_size */
word left_over; /* size of last chunk < copy_size */
if (n == 0)
return;
srcend = src + n; /* point at byte after src data */
destend = dest + n; /* point at byte after dest area */
if ((destend <= src) || (srcend <= dest)) /* not overlapping */
memcopy(dest,src,n);
else { /* overlapping data areas */
if (dest < src) {
/*
* The move is from higher memory to lower memory.
*/
copy_size = DiffPtrs(src,dest);
/* now loop round copying copy_size chunks of data */
do {
memcopy(dest,src,copy_size);
dest = src;
src = src + copy_size;
}
while (DiffPtrs(srcend,src) > copy_size);
left_over = DiffPtrs(srcend,src);
/* copy final fragment of data - if there is one */
if (left_over > 0)
memcopy(dest,src,left_over);
}
else if (dest > src) {
/*
* The move is from lower memory to higher memory.
*/
copy_size = DiffPtrs(destend,srcend);
/* now loop round copying copy_size chunks of data */
do {
destend = srcend;
srcend = srcend - copy_size;
memcopy(destend,srcend,copy_size);
}
while (DiffPtrs(srcend,src) > copy_size);
left_over = DiffPtrs(srcend,src);
/* copy intial fragment of data - if there is one */
if (left_over > 0) memcopy(dest,src,left_over);
}
} /* end of overlapping data area code */
/*
* Note that src == dest implies no action
*/
}
/*
* sweep - sweep the stack, marking all descriptors there. Method
* is to start at a known point, specifically, the frame that the
* fp points to, and then trace back along the stack looking for
* descriptors and local variables, marking them when they are found.
* The sp starts at the first frame, and then is moved down through
* the stack. Procedure, generator, and expression frames are
* recognized when the sp is a certain distance from the fp, gfp,
* and efp respectively.
*
* Sweeping problems can be manifested in a variety of ways due to
* the "if it can't be identified it's a descriptor" methodology.
*/
novalue sweep(ce)
struct b_coexpr *ce;
{
register word *s_sp;
register struct pf_marker *fp;
register struct gf_marker *s_gfp;
register struct ef_marker *s_efp;
word nargs, type, gsize;
fp = ce->es_pfp;
s_gfp = ce->es_gfp;
if (s_gfp != 0) {
type = s_gfp->gf_gentype;
if (type == G_Psusp)
gsize = Wsizeof(*s_gfp);
else
gsize = Wsizeof(struct gf_smallmarker);
}
s_efp = ce->es_efp;
s_sp = ce->es_sp;
nargs = 0; /* Nargs counter is 0 initially. */
while ((fp != 0 || nargs)) { /* Keep going until current fp is
0 and no arguments are left. */
if (s_sp == (word *)fp + Vwsizeof(*pfp) - 1) {
/* sp has reached the upper
boundary of a procedure frame,
process the frame. */
s_efp = fp->pf_efp; /* Get saved efp out of frame */
s_gfp = fp->pf_gfp; /* Get save gfp */
if (s_gfp != 0) {
type = s_gfp->gf_gentype;
if (type == G_Psusp)
gsize = Wsizeof(*s_gfp);
else
gsize = Wsizeof(struct gf_smallmarker);
}
s_sp = (word *)fp - 1; /* First argument descriptor is
first word above proc frame */
nargs = fp->pf_nargs;
fp = fp->pf_pfp;
}
else if (s_gfp != NULL && s_sp == (word *)s_gfp + gsize - 1) {
/* The sp has reached the lower end
of a generator frame, process
the frame.*/
if (type == G_Psusp)
fp = s_gfp->gf_pfp;
s_sp = (word *)s_gfp - 1;
s_efp = s_gfp->gf_efp;
s_gfp = s_gfp->gf_gfp;
if (s_gfp != 0) {
type = s_gfp->gf_gentype;
if (type == G_Psusp)
gsize = Wsizeof(*s_gfp);
else
gsize = Wsizeof(struct gf_smallmarker);
}
nargs = 1;
}
else if (s_sp == (word *)s_efp + Wsizeof(*s_efp) - 1) {
/* The sp has reached the upper
end of an expression frame,
process the frame. */
s_gfp = s_efp->ef_gfp; /* Restore gfp, */
if (s_gfp != 0) {
type = s_gfp->gf_gentype;
if (type == G_Psusp)
gsize = Wsizeof(*s_gfp);
else
gsize = Wsizeof(struct gf_smallmarker);
}
s_efp = s_efp->ef_efp; /* and efp from frame. */
s_sp -= Wsizeof(*s_efp); /* Move past expression frame marker. */
}
else { /* Assume the sp is pointing at a
descriptor. */
if (Qual(*((dptr)(&s_sp[-1]))))
postqual((dptr)&s_sp[-1]);
else if (Pointer(*((dptr)(&s_sp[-1]))))
markblock((dptr)&s_sp[-1]);
s_sp -= 2; /* Move past descriptor. */
if (nargs) /* Decrement argument count if in an*/
nargs--; /* argument list. */
}
}
}
#ifdef DeBugIconx
/*
* descr - dump a descriptor. Used only for debugging.
*/
novalue descr(dp)
dptr dp;
{
int i;
fprintf(stderr,"%08lx: ",(long)dp);
if (Qual(*dp))
fprintf(stderr,"%15s","qualifier");
else if (Var(*dp) && !Tvar(*dp))
fprintf(stderr,"%15s","variable");
else {
i = Type(*dp);
switch (i) {
case T_Null:
fprintf(stderr,"%15s","null");
break;
case T_Integer:
fprintf(stderr,"%15s","integer");
break;
default:
fprintf(stderr,"%15s",blkname[i]);
}
}
fprintf(stderr," %08lx %08lx\n",(long)dp->dword,(long)IntVal(*dp));
}
/*
* blkdump - dump the allocated block region. Used only for debugging.
*/
novalue blkdump()
{
register char *blk;
register word type, size, fdesc;
register dptr ndesc;
fprintf(stderr,
"\nDump of allocated block region. base:%08lx free:%08lx max:%08lx\n",
(long)blkbase,(long)blkfree,(long)blkend);
fprintf(stderr," loc type size contents\n");
for (blk = blkbase; blk < blkfree; blk += BlkSize(blk)) {
type = BlkType(blk);
size = BlkSize(blk);
fprintf(stderr," %08lx %15s %4ld\n",(long)blk,blkname[type],
(long)size);
if ((fdesc = firstd[type]) > 0)
for (ndesc = (dptr)(blk + fdesc);
ndesc < (dptr)(blk + size); ndesc++) {
fprintf(stderr," ");
descr(ndesc);
}
fprintf(stderr,"\n");
}
fprintf(stderr,"end of block region.\n");
}
#endif /* DeBugIconx */